import java.util.Vector;

public class Queue {

  /* List of customers in the queue */
  protected Vector customers;
  /* sum of waiting times of the customers */
  protected double sumW;
  /* sum of squares of the waiting times of the customers */
  protected double sumW2;
  /* sum of sojourn times of the customers */
  protected double sumS;
  /* sum of squares of the sojourn times of the customers */
  protected double sumS2;
  /* total number of customers that have been in this queue */
  protected int n;
  /* surface under graph (Nr of customers in queue) * time */
  protected double surface;
  /* total time until the last arrival or removal of a customer */
  protected double t;
  
  
  /**
   * Constructs an empty Queue
   */
   
  public Queue() {
    customers = new Vector();
    sumW = 0;
    sumW2 = 0;
    sumS = 0;
    sumS2 = 0;
    n = 0;
    surface = 0;
    t = 0;
  }
  
  /** 
   * Returns the number of customers in the queue (including the person in service)
   * @return the number of customers
   */
   
  public int getSize() {
    return customers.size();
  }
  
  /**
   * Adds a customer to this queue
   * @param c the new customer
   */
   
  public void addCustomer(Customer c) {
    int size = customers.size();
    double currentTime = c.getArrivalTime();
    surface += size * (currentTime - t);
    t = currentTime;
    customers.addElement(c);
  }
  
  /**
   * Removes the first customer from the queue at time <i>t</i>
   * @param t the time that the customer is removed
   * @return the customer that is removed from the queue
   */
   
  public Customer removeCustomer(double currentTime) {
    Customer c = (Customer) customers.elementAt(0);
    sumS += currentTime - c.getArrivalTime();
    sumS2 += (currentTime - c.getArrivalTime()) * (currentTime - c.getArrivalTime());
    sumW += currentTime - c.getArrivalTime() - c.getServiceTime();
    sumW2 += (currentTime - c.getArrivalTime() - c.getServiceTime()) * (currentTime - c.getArrivalTime() - c.getServiceTime());
    n++;
    int size = customers.size();
    surface += size * (currentTime - t);
    t = currentTime;
    customers.removeElementAt(0);
    return c;
  }

  /**
   * Returns the customer at position <i>index</i>
   * @param index the position of the customer in the queue (0 = in service)
   */
   
  public Customer getCustomerAt(int index) {
    return (Customer) customers.elementAt(index);
  }
  
  /**
   * Returns the mean waiting time of all customers that have been in the queue.
   * @return mean(W)
   */
   
  public double getMeanWaitingTime() {
    return sumW / n;
  } 
   
  /**
   * Returns the mean sojourn time of all customers that have been in the queue.
   * @return mean(S)
   */
   
  public double getMeanSojournTime() {
    return sumS / n;
  } 
   
  /**
   * Returns the variance of the waiting time of all customers that have been in the queue.
   * @return var(W)
   */
   
  public double getVarianceWaitingTime() {
    return (sumW2 - sumW*sumW/n)/(n-1);
  }
  
  /**
   * Returns the variance of the sojourn time of all customers that have been in the queue.
   * @return var(S)
   */
   
  public double getVarianceSojournTime() {
    return (sumS2 - sumS*sumS/n)/(n-1);
  }
  
  /**
   * Returns the mean number of customers in this queue.
   * @return the mean(L)
   */
   
  public double getMeanNumberOfCustomers() {
    return surface / t;
  }
   
} 